//
// Created by gogoqiu on 2021/9/25.
//
#include "model/MyTagApp.h"
#include "QueryGitIP.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <rapidsvn_app.hpp>
#include <wx/wfstream.h>
#include <wx/protocol/http.h>
#include <wx/url.h>

size_t QueryGitIpAction::write_data ( void* buffer, size_t size, size_t nmemb, void *stream )
{
    auto *ptr = ( QueryGitIpAction* ) stream;
    //FILE *fptr = (FILE*)stream;
    //fwrite(buffer,size,nmemb,fptr);
    //printf("%s\r\n", (char *)buffer);
    int bytes = size * nmemb;
    ptr->len += bytes;
    char buf[ bytes + 1 ];
    memset ( buf, 0, bytes + 1 );
    memcpy ( buf, buffer, bytes );
    ptr->responseBody += buf;
    return bytes;
}

bool QueryGitIpAction::Prepare()
{
    //return NormalAction::Prepare();
    //setup a dialog

    return true;
}

bool QueryGitIpAction::Perform()
{
    if( httpType== HTTP_CURL ) {
        return curlHttp();
    }else if( httpType==HTTP_WX ){
        //use wxHttp
        return wxHttp();
    }
}

bool QueryGitIpAction::curlHttp(){
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (!curl) {
        fprintf(stderr, "curl init failed\n");
        return -1;
    }
    MyPreferenceCore *preferenceCore = ((MyPreferenceCore *) myTagApp->getPreferenceCore());
    wxString url = preferenceCore->get_query_git_url();
    const char *POST_URL = url.operator const char *();
    //printf("url: %s\n", POST_URL );

    curl_easy_setopt (curl, CURLOPT_URL, POST_URL); //url地址
    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0); //不检查ssl，可访问https
    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0); //不检查ssl，可访问https
    //curl_easy_setopt(curl,CURLOPT_POSTFIELDS,POSTFIELDS); //post参数
    curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, QueryGitIpAction::write_data); //对返回的数据进行操作
    curl_easy_setopt (curl, CURLOPT_WRITEDATA, this); //这是write_data的第四个参数值
    curl_easy_setopt (curl, CURLOPT_POST, 1); //设置问非0表示本次操作为post
    curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); //打印调试信息

    //curl_easy_setopt(curl,CURLOPT_HEADER,1); //将响应头信息和相应体一起传给
    //curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Content-Type:text/plain");
    curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); //设置为非0,响应头信息location
    curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 10);
    curl_easy_setopt (curl, CURLOPT_TIMEOUT, 10); //接收数据时超时设置，如果10秒内数据未
    //curl_easy_setopt(curl,CURLOPT_COOKIEFILE,"/Users/zhu/CProjects

    res = curl_easy_perform(curl);

    if (res != CURLE_OK) {
        switch (res) {
            case CURLE_UNSUPPORTED_PROTOCOL:
                fprintf(stderr, "不支持的协议,由URL的头部指定\n");
            case CURLE_COULDNT_CONNECT:
                fprintf(stderr, "不能连接到remote主机或者代理\n");
            case CURLE_HTTP_RETURNED_ERROR:
                fprintf(stderr, "http返回错误\n");
            case CURLE_READ_ERROR:
                fprintf(stderr, "读本地文件错误\n");
            default:
                fprintf(stderr, "返回值:%d\n", res);
        }
        return false;
    }

    curl_easy_cleanup(curl);
    return true;
}

bool QueryGitIpAction::wxHttp(){
    wxHTTP* url_handler = nullptr;
    /*
	AddDebugLogLineN(logHTTP, wxT("HTTP download thread started"));

	const CProxyData* proxy_data = thePrefs::GetProxyData();
	bool use_proxy = proxy_data != nullptr && proxy_data->m_proxyEnable;
    */
    MyPreferenceCore *preferenceCore = ((MyPreferenceCore *) myTagApp->getPreferenceCore());
    wxString _url = preferenceCore->get_query_git_url();
    //const char *POST_URL = url.operator const char *();

    wxURL url(_url) ;
    //
    url_handler = new wxHTTP;
    url_handler->SetProxyMode(false);
    /*
    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(port);
     */
    //
    /*
    if (!url_handler->Connect(addr, true)) {
        throw wxString(_("Unable to connect to HTTP download server"));
    }*/
    wxInputStream* url_read_stream = url.GetInputStream();

    //wxInputStream* url_read_stream = url_handler->GetInputStream(url);
    //wxInputStream* url_read_stream = url_handler->GetInputStream(location_url);

    if( url_read_stream== nullptr ){
        //!!, fail

    }
    /* store the HTTP response code */
    int response = url_handler->GetResponse();

    /* store the HTTP error code */
    wxProtocolError error = url_handler->GetError();

    //wxBufferedOutputStream out(wxT("test"));
    //out.Write(*url_read_stream);

    //
    //wxInputStream *url_read_stream = (GetInputStream(url_handler, url ));
    //int download_size = url_read_stream->GetSize();
    //wxInputStream* url_read_stream = url_handler->GetInputStream(location_url);

    if (url_handler) {
        url_handler->Destroy();
    }

    //AddDebugLogLineN(logHTTP, wxT("HTTP download thread ended"));
    //return nullptr;
    return true;
}

wxInputStream* QueryGitIpAction::GetInputStream(wxHTTP * & url_handler, const wxString& location )
{
    // Extract the protocol name
    wxString protocol(location.BeforeFirst(wxT(':')));

    wxString host = location.Right(location.Len() - 7); // strlen("http://") -> 7

    // I believe this is a bug...
    // Sometimes "Location" header looks like this:
    // "http://www.whatever.com:8080http://www.whatever.com/downloads/something.zip"
    // So let's clean it...

    int bad_url_pos = host.Find(wxT("http://"));
    wxString location_url;
    if (bad_url_pos != -1) {
        // Malformed Location field on header (bug above?)
        location_url = host.Mid(bad_url_pos);
        host = host.Left(bad_url_pos);
        // After the first '/' non-http-related, it's the location part of the URL
        location_url = location_url.Right(location_url.Len() - 7).AfterFirst(wxT('/'));
    } else {
        // Regular Location field
        // After the first '/', it's the location part of the URL
        location_url = host.AfterFirst(wxT('/'));
        // The host is everything till the first "/"
        host = host.BeforeFirst(wxT('/'));
    }

    // Build the cleaned url now
    wxString url = wxT("http://") + host + wxT("/") + location_url;

    int port = 80;
    if (host.Find(wxT(':')) != -1) {
        // This http url has a port
        port = wxAtoi(host.AfterFirst(wxT(':')));
        host = host.BeforeFirst(wxT(':'));
    }

    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(port);
    //
    if (!url_handler->Connect(addr, true)) {
        throw wxString(_("Unable to connect to HTTP download server"));
    }

    //wxInputStream* url_read_stream = url_handler->GetInputStream(url);
    wxInputStream* url_read_stream = url_handler->GetInputStream(location_url);

    if( url_read_stream== nullptr ){
        //!!, fail

    }
    /* store the HTTP response code */
    int response = url_handler->GetResponse();

    /* store the HTTP error code */
    wxProtocolError error = url_handler->GetError();

    //AddDebugLogLineN(logHTTP, CFormat(wxT("Host: %s:%i\n")) % host % port);
    //AddDebugLogLineN(logHTTP, CFormat(wxT("URL: %s\n")) % url);
    //AddDebugLogLineN(logHTTP, CFormat(wxT("Response: %i (Error: %i)")) % m_response % m_error);

    if (!response) {
        //AddDebugLogLineC(logHTTP, wxT("WARNING: Void response on stream creation"));
        // WTF? Why does this happen?
        // This is probably produced by an already existing connection, because
        // the input stream is created nevertheless. However, data is not the same.
        delete url_read_stream;
        throw wxString(_("Invalid response from HTTP download server"));
    }

    if (response == 301  // Moved permanently
        || response == 302 // Moved temporarily
        // What about 300 (multiple choices)? Do we have to handle it?
            ) {

        // We have to remove the current stream.
        delete url_read_stream;

        wxString new_location = url_handler->GetHeader(wxT("Location"));
        //AddDebugLogLineN(logHTTP, CFormat(wxT("Redirecting to: %s")) % new_location);

        url_handler->Destroy();

    } else if (response == 304) {		// "Not Modified"
        delete url_read_stream;
        url_handler->Destroy();
        url_read_stream = nullptr;
        url_handler = nullptr;
    }

    return url_read_stream;
}

QueryGitIpAction::QueryGitIpAction ( MyTagApp *myTagApp1, wxWindow *parent, wxString name )
        : NormalAction ( myTagApp1, parent, name )
{
    responseBody = "";
    len = 0;
    httpType = HTTP_CURL;
}


